import time

from .alib import alib
def tibble的程getのfromCsv(args):
    #try to read a tibble intelligently from a text file
    #judge data type and header automatically
    # https://pandas.pydata.org/pandas-docs/version/0.21/generated/pandas.read_csv.html

    fn=args

    import pandas as pd
    try:
        df=pd.read_csv(fn,header=0,engine='python',encoding='utf-8',index_col=0)
    except pd.errors.ParserError:
        with open(fn,encoding='utf8') as f:
            l=f.readline()
        #print(l)
        df=pd.read_csv(fn,names=l[:-1].split(','),engine='python',encoding='utf-8',index_col=0,skiprows=1)

    ans=df    
    return None if 'ans' not in locals() else ans

def alib的程doのsinflate(args):
    # simple inflate ones starting with !:

    al=args

    def imbue(s):
        if s.startswith('!:'):
            try:
                ret=eval(s[2:])
            except:
                print('Something wrong for imbue string{s}')
                ret=s
        else:
            ret=s
        #print(f'Checked {s}, result={ret}')
        return ret

    nexts=[al] #try to scan leaf nodes
    while len(nexts)>0:
        a=nexts.pop()
        for k in a:
            
            if isinstance(a[k],alib):
                nexts.append(a[k])
            else:
                a[k]=imbue(a[k])

    ans=al    
    return None if 'ans' not in locals() else ans

def uniformity的程toolのloadConf(mapConf):
    # load and check configuration file
    
    o=alib().Load(mapConf)
    alib的程doのsinflate(o)
    return o

def pyplot的程getのrectangle(args):
    # return a rectangle patch that can be added to axes

    opt=args# [bl|bottom left][tr|top right][#color]

    import matplotlib.patches as mps

    width=opt.tr[0]-opt.bl[0]
    height=opt.tr[1]-opt.bl[1]

    opt2=opt.copy()
    opt2.pop('tr')
    opt2.pop('bl')

    ans=mps.Rectangle(opt.bl,width,height,**opt2)    
    return None if 'ans' not in locals() else ans

def statistics的程getのsimple(args):
    #print the simple statistics of the numbers in the input iterable

    import numpy as np
    ans=alib()
    ans['count']=len(args)
    ans['mean']=np.mean(args)
    ans['std']=np.std(args)
    #print(ans.ToString(''))    
    return None if 'ans' not in locals() else ans

def colormap的程getのmappable(args):
    #get the scalar mappable with a colormap name

    if isinstance(args,str):
        name=args
        vmin,vmax=0,1
    else:
        name=args['name']
        vmin=args.vmin
        vmax=args.vmax
        log=True if 'log' in args and args.log else False

    import matplotlib.pyplot as plt
    from matplotlib import cm, colors

    cmap=plt.get_cmap(name)
    if log:
        cNorm=colors.LogNorm(vmin=vmin,vmax=vmax)
    else:
        cNorm=colors.Normalize(vmin=vmin,vmax=vmax)

    ans=cm.ScalarMappable(norm=cNorm,cmap=cmap)


    if isinstance(args,alib):
        args['cmap']=cmap
        args['norm']=cNorm    
    return None if 'ans' not in locals() else ans

def uniformity的程toolのprocessData(data,vname):
    # process data for drawing

    draw=data.conf.draw
    lName=data.ext[draw.posKey]
    lVal=data.ext[vname]

    import re
    pat=re.compile(draw.pattern)
    
    dPlaces=alib()
    # fetch values
    for n,v in zip(lName,lVal):
        m=pat.match(n)
        if m:
            place=m.group('place')
            if place in dPlaces:
                dPlaces[place].append(v)
            else:
                dPlaces[place]=[v]
        else:
            print(f'Wrong name: {n}')

    # calculate mean
    Stat=statistics的程getのsimple
    for p in dPlaces:
        dPlaces[p]=Stat(dPlaces[p])

    data.setValue('t',dPlaces)
    data.setValue('bUpper',max(lVal))
    data.setValue('bLower',min(lVal))

    #print(dPlaces.ToString(''))

    m=pat.match(lName[0])
    typ=m.group('type')
    if typ in data.conf.devices:
        if vname in data.conf.devices[typ]:
            data.setValue('aDevPar',data.conf.devices[typ][vname])
        else:
            data.setValue('aDevPar','')
            print(f'but did not found mapping config for {vname}, using default')
    else:
        print(f'but did not found mapping config for Type {typ}, using default')    
    return None if 'ans' not in locals() else ans

def colormap的程getのcolorbar(args):
    # get the colorbar legend
    # https://www.matplotlib.org.cn/tutorials/colors/colorbar_only.html#basic-continuous-colorbar

    opt=args #[ax][cmap][norm][orientation][#extras|[extend|both][extendfrac|auto]]

    if 'extras' not in opt:
        
        opt['extras']=alib()
    import matplotlib as mpl

    cb=mpl.colorbar.ColorbarBase(opt.ax,cmap=opt.cmap,norm=opt.norm,orientation=opt.orientation,**opt.extras)

    cb.set_label(opt.label,fontsize=20)

    ans=cb    
    return None if 'ans' not in locals() else ans

def drawMap(dataFile,mapConf,valueName='Ion',file=None,cmap='coolwarm'):
    # draw the map

    #console=M.shelf.uniformity.console
    
    
    data = alib()
    data['ext'] = tibble的程getのfromCsv(dataFile)
    data['conf'] = uniformity的程toolのloadConf(mapConf)
    dPlace=data.conf.places
    draw=data.conf.draw
    vname=valueName
    import os 
    name=dataFile.split('/')[-1]

    uniformity的程toolのprocessData(data,vname)

    aData=data.t

    import matplotlib.pyplot as plt

    fig,ax=plt.subplots(figsize=(8,6))

    dispName=vname
    dispL=data.bLower
    dispH=data.bUpper
    dispLog=False
    cmapName=cmap
    if data.aDevPar:
        adp=data.aDevPar
        if 'dispName' in adp:
            dispName=adp.dispName
        if 'dispL' in adp:
            dispL,dispH=adp.ToList(['dispL','dispH'])
        if 'log' in adp:
            dispLog=True
        if 'cmap' in adp:
            cmapName=adp.cmap

    mapOpt=alib(f'[name|{cmapName}]',vmin=dispL,vmax=dispH,log=dispLog)
    scMap=colormap的程getのmappable(mapOpt)


    Rect=pyplot的程getのrectangle
    #ax.plot([0,80],[0,80])
    for p in aData:
        if p in dPlace:
            bl=dPlace[p].posBL
            sz=dPlace[p]['size']
            tr=(bl[0]+sz[0],bl[1]+sz[1])
            color=scMap.to_rgba(aData[p].mean)
            ax.add_patch(Rect(alib('',bl=bl,tr=tr,color=color)))
            #print(f'added patch {color}')
            plt.title(f'{name} - {vname}')
        else:
            print(f'wrong place {p}')
    #ax.set_xlim(*draw.viewXlim)
    #ax.set_ylim(*draw.viewYlim)
    plt.axis('equal')
    if 'code' in draw:
        ast=compile(draw.code,'conf draw.code','exec')
        exec(ast)
    else:
        plt.axis('off')
    fig.subplots_adjust(bottom=0.25)

    ax2=fig.add_subplot(111,position=(0.2,.13,.6,.05))
    mapOpt['orientation']='horizontal'
    mapOpt['label']=dispName
    mapOpt['ax']=ax2
    mapOpt['extras']=alib('[extend|both]')
    cb=colormap的程getのcolorbar(mapOpt)
    if file:
        plt.savefig(file)
    else:
        plt.show()    
    return None if 'ans' not in locals() else ans